import React, { useState, useEffect, useCallback } from 'react';
import Autocomplete from '@mui/material/Autocomplete';
import TextField from '@mui/material/TextField';
import CircularProgress from '@mui/material/CircularProgress';
import Fuse from 'fuse.js';

// Define types
interface Option {
  id: number;
  name: string;
  desc: string;
}

interface AsyncAutocompleteProps {
  /**
   * Custom debounce time in milliseconds
   */
  debounceTime?: number;
  
  /**
   * Custom function to fetch results
   */
  fetchResults?: (term: string) => Promise<Option[]>;
  
  /**
   * Custom function to sort results
   */
  sortResults?: (options: Option[]) => Option[];
  
  /**
   * Custom function to determine if request should be aborted
   */
  shouldAbort?: (term: string) => Promise<boolean>;
  
  /**
   * Custom function to render option
   */
  renderOption?: (props: React.HTMLAttributes<HTMLLIElement>, option: Option) => React.ReactNode;
}

const AsyncAutocomplete = ({
  debounceTime = 300,
  fetchResults: customFetchResults,
  sortResults,
  shouldAbort,
  renderOption: customRenderOption
}: AsyncAutocompleteProps) => {
  const [inputValue, setInputValue] = useState('');
  const [options, setOptions] = useState<Option[]>([]);
  const [activeAbortController, setActiveAbortController] = useState<AbortController | null>(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  // Default implementation of fetchResults
  const defaultFetchResults = useCallback(
    (term: string): Promise<Option[]> => {
      const controller = new AbortController();
      setActiveAbortController(controller);
      setLoading(true);
      setError(null);

      return fetch(`https://jsonplaceholder.typicode.com/users?search=${term}`, {
        signal: controller.signal,
      })
        .then((res) => res.json())
        .catch((error) => {
          if (error.name !== 'AbortError') {
            console.error('Fetch error:', error);
            setError('搜索失败，请重试');
          }
          return [];
        })
        .finally(() => {
          setLoading(false);
        });
    },
    []
  );

  // Use custom or default fetch function
  const fetchFunction = customFetchResults || defaultFetchResults;

  // Using Fuse.js for fuzzy search
  const fuse = new Fuse(options, { keys: ['name', 'desc'] });

  // Implement debounce and request abort mechanism
  useEffect(() => {
    if (!inputValue.trim()) {
      setOptions([]);
      return;
    }

    const executeSearch = async () => {
      // Check if request should be aborted
      if (shouldAbort) {
        const abort = await shouldAbort(inputValue);
        if (abort) {
          return;
        }
      }

      // Abort previous request if exists
      if (activeAbortController) {
        activeAbortController.abort();
      }

      // Fetch new results
      const data = await fetchFunction(inputValue);
      
      // Apply custom sorting if provided
      const sortedData = sortResults ? sortResults(data) : data;
      setOptions(sortedData);
    };

    const timer = setTimeout(executeSearch, debounceTime);

    return () => {
      clearTimeout(timer);
    };
  }, [inputValue, fetchFunction, debounceTime, shouldAbort, sortResults]);

  // Multi-property filtering
  const filteredOptions = fuse.search(inputValue).map((result) => result.item);

  // Default render option
  const defaultRenderOption = (props: React.HTMLAttributes<HTMLLIElement>, option: Option) => (
    <li {...props} key={option.id}>
      <div>
        <strong>{option.name}</strong>
        <p style={{ fontSize: '0.8em', color: 'gray' }}>{option.desc}</p>
      </div>
    </li>
  );

  // Use custom or default render option
  const renderOptionFunction = customRenderOption || defaultRenderOption;

  return (
    <div style={{ maxWidth: 400, margin: 'auto', padding: '2rem' }}>
      <Autocomplete
        options={filteredOptions}
        inputValue={inputValue}
        onInputChange={(event, newInputValue) => {
          setInputValue(newInputValue);
        }}
        getOptionLabel={(option) => typeof option === 'string' ? option : option.name}
        renderOption={renderOptionFunction}
        renderInput={(params) => (
          <TextField
            {...params}
            label="Search"
            error={!!error}
            helperText={error || ''}
            InputProps={{
              ...params.InputProps,
              endAdornment: (
                <React.Fragment>
                  {loading ? <CircularProgress color="inherit" size={20} /> : null}
                  {params.InputProps.endAdornment}
                </React.Fragment>
              ),
            }}
          />
        )}
        freeSolo // Support free text input
      />
    </div>
  );
};

export default AsyncAutocomplete;